package iss.java.list;
import java.util.concurrent.locks.ReadWriteLock;  
import java.util.concurrent.locks.ReentrantReadWriteLock; 
/**
 * Created by wenke on 2016/9/16.
 * // TODO: Modify this class to meet requirement B and C.
 */
public class MyList {
    // two guards. Do not call remove() on them!!
    private Node head;
    private Node tail;
    private int size;
    private ReadWriteLock lock = new ReentrantReadWriteLock(false);  
    public MyList() {
        head = new Node(lock).setData(0);
        tail = new Node(lock).setData(0).setNext(null).setPrev(head);
        head.setNext(tail);
        size = 0;
    }

    public int getSize() {
    	lock.readLock().lock();
    	try {
    		return size;
    	} finally {
    		lock.readLock().unlock();
    	}
    }

    public Node getHead() {
    	lock.readLock().lock();
    	try {
    		return head;
    	} finally {
    		lock.readLock().unlock();
    	}
    }

    public Node getTail() {
    	lock.readLock().lock();
    	try {
    		return tail;
    	} finally {
    		lock.readLock().unlock();
    	}
    }

    /**
     * Insert a node with <pre>data</pre> after <pre>_prev</pre>.
     *
     * @param _prev
     * @param data
     * @return The node just inserted.
     */
    public Node insert(Node _prev, int data) {
    	lock.writeLock().lock();
    	Node node = new Node(lock);
    	try {
    		node.setData(data).setNext(_prev.getNext()).setPrev(_prev);
            _prev.getNext().setPrev(node);
            _prev.setNext(node);
            ++size;
            return node;
    	} finally {
    		lock.writeLock().unlock();
    	}
    	
    }

    /**
     * Remove the node <pre>target</pre>.
     *
     * @param target The node to remove.
     * @return the previous node of target.
     */
    public Node remove(Node target) {
        if (target == head || target == tail)
            throw new RuntimeException("DO NOT remove the head or tail node. They are guards.");
        // shortcut "target"
        if (target.getLock() != lock) 
        	throw new RuntimeException("Target does not belong to List!");
        
        Node prev = target.getPrev();
        Node next = target.getNext();
        lock.writeLock().lock();
        try {
        prev.setNext(next);
        next.setPrev(prev);
        --size;
        return prev;
        } finally {
        	lock.writeLock().unlock();
        }
        // Unlike C/C++, the memory of "target" is automatically recycled by GC
        // return the previous one because it is quite likely to insert a new node after prev;
    }

}
